package com.szsh.aiot.hsm.thirdService;

import com.google.gson.Gson;
import com.szsh.aiot.hsm.dto.area.IAreaSpe;
import com.szsh.aiot.hsm.dto.gateway.GatewayInfo;
import com.szsh.aiot.hsm.dto.gateway.GatewayQueryByPhoneResponse;
import com.szsh.aiot.hsm.dto.gateway.GatewayQueryResponse;
import com.szsh.aiot.hsm.dto.gateway.IGatewayInfo;
import com.szsh.aiot.hsm.mapper.IAreaMapper;
import com.szsh.aiot.hsm.utils.JsonConvert;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 网关信息查询客户端：提供手机号码、宽带账号、mac地址互查功能
 *
 * @author zhangtt
 */
@Component
public class GatewayInfoQueryClient {
    private static final String PHONE_PREFIX = "gateByPhone:";
    private static final String PPPOE_PREFIX = "gateByPPOE:";
    private static final Logger LOGGER = LoggerFactory.getLogger(GatewayInfoQueryClient.class);

    @Value("${hsm.gateway.validtime}")
    private int validtime;

    @Value("${hsm.gateway.endpoint}")
    private String gatewayURL;

    @Value("${hsm.ability.headerAppID}")
    private String appId;

    @Value("${hsm.ability.headerAppKey}")
    private String appKey;

    @Value("${hsm.gateway.cache}")
    private int cache;

    @Autowired
    private RestTemplate restTemplate;

    @Resource
    private IAreaMapper areaMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    Gson gson = new Gson();

    /**
     * 根据宽带账号查询网关信息
     * 判断是否走缓存
     *
     * @param ppoename 宽带号
     * @return GatewayInfo 网关信息
     */
    public GatewayInfo queryByPPOE(String ppoename) {
        if (cache == 1) {
            return cacheByPhoneByPPOE(ppoename);
        } else {
            return queryGatewayByPppoe(ppoename);
        }
    }

    /**
     * 根据宽带账号查询网关信息
     * 缓存
     *
     * @param ppoename 宽带号
     * @return GatewayInfo 网关信息
     */
    private GatewayInfo cacheByPhoneByPPOE(String ppoename) {
        String key = getPppoeKey(ppoename);
        String json = redisTemplate.opsForValue().get(key);
        if (StringUtils.isNotBlank(json)) {
            // 查询 redis 成功
            return gson.fromJson(json,GatewayInfo.class);
        } else {
            GatewayInfo info = queryGatewayByPppoe(ppoename);
            if (info != null) {
                redisTemplate.opsForValue().set(key, gson.toJson(info),
                        validtime, TimeUnit.HOURS);
            }
            return info;
        }
    }

    /**
     * 通过宽带号查询宽带信息
     *
     * @param ppoename 宽带号
     * @return GatewayInfo 网关信息
     */
    public GatewayInfo queryGatewayByPppoe(String ppoename) {
        return queryGatewayByPppoe(ppoename, 1);
    }

    public static void main(String[] args) {
        String body =
                "{\"result\":\"1\",\"message\":\"success\",\"data\":{\"MAC\":\"CC242E220350\",\"BINDING_DATE\":\"2022-09-08 19:53:48\",\"PHONE\":\"18158110218\",\"PROVINCE\":\"浙江\",\"CITY\":\"杭州\",\"MODEL\":\"ZNHG600\",\"VENDOR\":\"zhaoneng\",\"ACCESS_TIME\":\"2021-10-02 09:43:49\",\"PPPOENAME\":\"057177746420\",\"DEVICE_OS\":\"CTWRT\",\"MIDDLE\":\"FW2.1_CT_ZNXT_MT7526_R3545\",\"HARD\":\"V1.0\"}}\n";
        GatewayQueryResponse gatewayQueryResponse = new Gson().fromJson(body,GatewayQueryResponse.class);
        System.out.println(new Gson().toJson(gatewayQueryResponse));
    }

    /**
     * 通过宽带号查询宽带信息
     *
     * @param ppoename 宽带号
     *
     *
     * @param tryCount 调用接口异常,重试次数
     * @return GatewayInfo 网关信息
     */
    public GatewayInfo queryGatewayByPppoe(String ppoename, int tryCount) {
        String url = gatewayURL + "?ppoename={1}";
        GatewayQueryResponse response = realCall(tryCount, url, GatewayQueryResponse.class, ppoename);
        LOGGER.info("response {}",new Gson().toJson(response));
        if (response == null || !"1".equals(response.getResult())) {
            return null;
        }
        LOGGER.info("{}宽带号查出的网关信息为{}",ppoename,new Gson().toJson(response.getData()).toString());
        return resultProcess(response.getData());
    }

    /**
     * 根据mac地址查询网关信息
     *
     * @param mac 网关MAC
     * @return GatewayInfo 网关信息
     */
    public GatewayInfo queryByMAC(String mac) {
        mac = mac.replace(":", "");
        // mac地址为无符号格式
        mac = mac.replace("-", "");
        String url = gatewayURL + "?mac={1}";
        GatewayQueryResponse response = realCall(url, GatewayQueryResponse.class, mac);
        if (response == null || !"1".equals(response.getResult())) {
            return null;
        }
        return resultProcess(response.getData());
    }

    /**
     * 根据手机号查询绑定的所有网关信息
     *
     * @param phone 手机号
     * @return GatewayInfo 小翼管家绑定的所有网关信息
     */
    public List<GatewayInfo> queryAllGatewayByPhone(String phone) {
        String url = gatewayURL + "?phone={1}";
        GatewayQueryByPhoneResponse response = realCall(url, GatewayQueryByPhoneResponse.class, phone);
        if (response == null || !"1".equals(response.getResult())) {
            return null;
        }
        if (CollectionUtils.isEmpty(response.getData())) {
            return null;
        }
        return response.getData();
    }

    /**
     *
     * @param url            请求地址
     * @param responseClass  返回的实体类
     * @param uriVariables   uri参数
     * @return 调用结果
     * @param <T> 返回实体
     */
    private <T> T realCall(String url, Class<T> responseClass, Object uriVariables) {
        return realCall(1, url, responseClass, uriVariables);
    }

    /**
     *
     * @param tryCount       调用接口异常,重试次数
     * @param url            请求地址
     * @param responseClass  返回的实体类
     * @param uriVariables   uri参数
     * @return 调用结果
     * @param <T> 返回实体
     */
    private <T> T realCall(int tryCount, String url, Class<T> responseClass, Object uriVariables) {
        String requestId = UUID.randomUUID().toString();
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Request :  {}, {}, {} ", requestId, url, uriVariables);
        }
        // 设置请求头
        MultiValueMap<String, String> multiValueMap = new LinkedMultiValueMap<>();

        multiValueMap.add("X-APP-ID", appId);
        multiValueMap.add("X-APP-KEY", appKey);
        multiValueMap.add("X-CTG-Request-Id", requestId);

        HttpEntity<Object> httpEntity = new HttpEntity<>(multiValueMap);

        ResponseEntity<String> responseEntity = null;
        for (int i = 0; i < tryCount; i++) {
            try {
                responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class, uriVariables);
                break;
            } catch (Exception e) {
                if (LOGGER.isErrorEnabled()) {
                    LOGGER.error("系统异常", e);
                }
            }
        }
        if (null == responseEntity) {
            return null;
        }

        String body = responseEntity.getBody();
        if (LOGGER.isInfoEnabled()) {
            LOGGER.info("Result : {}, {}, {}, {}", requestId, url, uriVariables, body);
        }
        return gson.fromJson(body,responseClass);
    }

    /**
     * 结果处理
     *
     * @param gatewayInfo 网关信息
     * @return GatewayInfo 网关信息
     */
    private GatewayInfo resultProcess(GatewayInfo gatewayInfo) {
        if (null == gatewayInfo) {
            return null;
        }
        if (org.springframework.util.StringUtils.isEmpty(gatewayInfo.getPppoename()) || org.springframework.util.StringUtils.isEmpty(gatewayInfo.getMac())) {
            return null;
        }
        try {
            //处理地区信息字段
            dealAreaInfo(gatewayInfo);
            // 兼容逻辑：1、网关名称：XXX-EPON 等同
            String model = gatewayInfo.getModel();
            // XXX;2、网关名称：XXX-GPON 等同 XXX
            if (model != null && (model.endsWith("-EPON") || model.endsWith("-GPON"))) {
                gatewayInfo.setModel(model.substring(0, model.length() - 5));
            }
            //处理插件版本信息字段
            dealMidInfo(gatewayInfo);
            //记录网关信息
          //  gatewayInfoMapper.insert(makeGateWay(gatewayInfo));
            return gatewayInfo;
        } catch (Exception e) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("系统异常", e);
            }
        }
        return null;
    }

    private void dealAreaInfo(GatewayInfo gatewayInfo) {

        Map<String, String> areaMap = new HashMap<>();
        if (!StringUtils.isEmpty(gatewayInfo.getProvince())) {
            String provinceKey = "sercurity.area.province:" + gatewayInfo.getProvince();
            areaMap = getCityInfo(provinceKey);
            gatewayInfo.setProvinceName(areaMap.get("provinceName"));
            gatewayInfo.setProvince(areaMap.get("province"));
        }
        if (!StringUtils.isEmpty(gatewayInfo.getCity())) {
            String cityKey = "sercurity.area.city:" + gatewayInfo.getCity();
            areaMap = getCityInfo(cityKey);
            gatewayInfo.setCityName(areaMap.get("cityName"));
            gatewayInfo.setCity(areaMap.get("city"));
        }
        LOGGER.info("provice={},city : {}，转换后={}", gatewayInfo.getProvince(),
                gatewayInfo.getCity(), gson.toJson(gatewayInfo));
    }

    private void dealMidInfo(GatewayInfo gatewayInfo) {
        try {
            if (StringUtils.isEmpty(gatewayInfo.getMiddle())) {
                gatewayInfo.setChipModel("");
                return;
            }
            String[] gatewayMiddleString = gatewayInfo.getMiddle().split("_");
            gatewayInfo.setChipModel(gatewayMiddleString[gatewayMiddleString.length - 2]);
        } catch (Exception e) {
            gatewayInfo.setChipModel("");
        }
    }

    private IGatewayInfo makeGateWay(GatewayInfo gatewayInfo) {
        IGatewayInfo info = new IGatewayInfo();
        info.setPhone(gatewayInfo.getPhone());
        info.setMiddle(gatewayInfo.getMiddle());
        info.setCity(gatewayInfo.getCity());
        info.setProvice(gatewayInfo.getProvince());
        info.setDeviceOs(gatewayInfo.getDeviceOS());
        info.setVendor(gatewayInfo.getVendor());
        info.setModel(gatewayInfo.getModel());
        info.setMac(gatewayInfo.getMac());
        info.setArea(gatewayInfo.getArea());
        info.setBroadbandNO(gatewayInfo.getPppoename());
        return info;
    }

    private Map<String, String> getCityInfo(String rediskey) {
        Map<String, String> resultMap = new HashMap<>();
        // Boolean fitle = redisTemplate.hasKey(rediskey);

            String value = redisTemplate.opsForValue().get(rediskey);
            if (!StringUtils.isEmpty(value)) {
                resultMap = gson.fromJson(value,Map.class);
               return resultMap;
            }

        if (rediskey.startsWith("sercurity.area.province")) {
            List<String> requestparam = Arrays.asList(rediskey.split(":"));
            String provice = requestparam.get(1);
            IAreaSpe provinceArea = areaMapper.getAreaSpeByAreaName(provice, 0);
            resultMap.put("provinceName", provinceArea == null ? provice : provinceArea.getAreaName());
            resultMap.put("province", provinceArea == null ? "" : provinceArea.getAreaNo());
            redisTemplate.opsForValue().set(rediskey,gson.toJson(resultMap));
        }

        if (rediskey.startsWith("sercurity.area.city")) {
            List<String> requestparam = Arrays.asList(rediskey.split(":"));
            String city = requestparam.get(1);
            IAreaSpe cityArea = areaMapper.getAreaSpeByAreaName(city, 1);
            resultMap.put("cityName", cityArea == null ? city : cityArea.getAreaName());
            resultMap.put("city", cityArea == null ? "" : cityArea.getAreaNo());
            redisTemplate.opsForValue().set(rediskey,gson.toJson(resultMap));
        }
        return resultMap;
    }

    private String getPhoneKey(String phone) {
        return PHONE_PREFIX + phone;
    }

    private String getPppoeKey(String broadbandNO) {
        return PPPOE_PREFIX + broadbandNO;
    }
}
